In [1]:
Copied!
# %pip install geoai-py
# %pip install geoai-py
Import libraries¶
In [2]:
Copied!
import geoai
import geoai
Download sample data¶
In [3]:
Copied!
raster_url = (
"https://huggingface.co/datasets/giswqs/geospatial/resolve/main/naip_train.tif"
)
vector_url = "https://huggingface.co/datasets/giswqs/geospatial/resolve/main/naip_train_buildings.geojson"
raster_url = (
"https://huggingface.co/datasets/giswqs/geospatial/resolve/main/naip_train.tif"
)
vector_url = "https://huggingface.co/datasets/giswqs/geospatial/resolve/main/naip_train_buildings.geojson"
In [4]:
Copied!
raster_path = geoai.download_file(raster_url)
raster_path = geoai.download_file(raster_url)
naip_train.tif: 0%| | 0.00/12.1M [00:00<?, ?B/s]
naip_train.tif: 2%|▏ | 213k/12.1M [00:00<00:10, 1.20MB/s]
naip_train.tif: 7%|▋ | 871k/12.1M [00:00<00:03, 3.51MB/s]
naip_train.tif: 28%|██▊ | 3.34M/12.1M [00:00<00:00, 12.0MB/s]
naip_train.tif: 100%|██████████| 12.1M/12.1M [00:00<00:00, 26.9MB/s]
In [5]:
Copied!
vector_path = geoai.download_file(vector_url)
vector_path = geoai.download_file(vector_url)
naip_train_buildings.geojson: 0%| | 0.00/456k [00:00<?, ?B/s]
naip_train_buildings.geojson: 42%|████▏ | 193k/456k [00:00<00:00, 1.65MB/s]
naip_train_buildings.geojson: 100%|██████████| 456k/456k [00:00<00:00, 3.43MB/s]
Initialize building footprint extraction pretrained model¶
The pretained model is adapted from the Esri building footprint extraction model for the USA. Credits to Esri for the model.
In [6]:
Copied!
extractor = geoai.BuildingFootprintExtractor()
extractor = geoai.BuildingFootprintExtractor()
Model path not specified, downloading from Hugging Face...
Model downloaded to: /home/runner/.cache/huggingface/hub/models--giswqs--geoai/snapshots/f519baf6bb6d3c8b37b4f1f98e8d6a57bbc21f57/building_footprints_usa.pth Model loaded successfully
In [7]:
Copied!
mask_path = extractor.save_masks_as_geotiff(
raster_path=raster_path,
output_path="building_masks.tif",
confidence_threshold=0.5,
mask_threshold=0.5,
)
mask_path = extractor.save_masks_as_geotiff(
raster_path=raster_path,
output_path="building_masks.tif",
confidence_threshold=0.5,
mask_threshold=0.5,
)
Processing masks with parameters: - Confidence threshold: 0.5 - Chip size: (512, 512) - Mask threshold: 0.5 Dataset initialized with 3 rows and 7 columns of chips Image dimensions: 2503 x 1126 pixels Chip size: 512 x 512 pixels Overlap: 25.0% (stride_x=384, stride_y=384) CRS: EPSG:26911
Processing raster with 6 batches
0%| | 0/6 [00:00<?, ?it/s]
17%|█▋ | 1/6 [00:11<00:57, 11.54s/it]
33%|███▎ | 2/6 [00:23<00:46, 11.66s/it]
50%|█████ | 3/6 [00:34<00:34, 11.50s/it]
67%|██████▋ | 4/6 [00:46<00:22, 11.48s/it]
83%|████████▎ | 5/6 [00:57<00:11, 11.40s/it]
100%|██████████| 6/6 [01:00<00:00, 8.47s/it]
100%|██████████| 6/6 [01:00<00:00, 10.02s/it]
Object masks saved to building_masks.tif
Convert raster to vector
In [8]:
Copied!
gdf = extractor.masks_to_vector(
mask_path=mask_path,
output_path="building_masks.geojson",
simplify_tolerance=1.0,
)
gdf = extractor.masks_to_vector(
mask_path=mask_path,
output_path="building_masks.geojson",
simplify_tolerance=1.0,
)
Converting mask to GeoJSON with parameters: - Mask threshold: 0.5 - Min object area: 100 - Max object area: None - Simplify tolerance: 1.0 - NMS IoU threshold: 0.5 - Regularize objects: True - Angle threshold: 15° from 90° - Rectangularity threshold: 70.0% Mask dimensions: (1126, 2503) Mask value range: 0 to 255 Found 632 potential objects
0%| | 0/632 [00:00<?, ?it/s]
11%|█ | 71/632 [00:00<00:00, 706.98it/s]
23%|██▎ | 146/632 [00:00<00:00, 727.71it/s]
35%|███▍ | 219/632 [00:00<00:00, 726.42it/s]
46%|████▋ | 293/632 [00:00<00:00, 729.63it/s]
58%|█████▊ | 367/632 [00:00<00:00, 730.84it/s]
70%|██████▉ | 441/632 [00:00<00:00, 728.74it/s]
81%|████████▏ | 514/632 [00:00<00:00, 726.94it/s]
93%|█████████▎| 587/632 [00:00<00:00, 722.21it/s]
100%|██████████| 632/632 [00:00<00:00, 723.67it/s]
Created 609 valid polygons
Object count after NMS filtering: 609 Regularizing 609 objects... - Angle threshold: 15° from 90° - Min orthogonality: 30.0% of angles - Min rectangularity: 70.0% of bounding box area
0%| | 0/609 [00:00<?, ?it/s]
21%|██ | 129/609 [00:00<00:00, 1286.78it/s]
42%|████▏ | 258/609 [00:00<00:00, 1287.32it/s]
65%|██████▌ | 398/609 [00:00<00:00, 1336.39it/s]
90%|████████▉ | 546/609 [00:00<00:00, 1389.02it/s]
100%|██████████| 609/609 [00:00<00:00, 1379.98it/s]
Regularization completed: - Total objects: 609 - Rectangular objects: 609 (100.0%) - Other regularized objects: 0 (0.0%) - Unmodified objects: 0 (0.0%) Saved 609 objects to building_masks.geojson
Option 2: Extract building footprints as vector¶
In [9]:
Copied!
output_path = "naip_buildings.geojson"
gdf = extractor.process_raster(
raster_path,
output_path="buildings.geojson",
batch_size=4,
confidence_threshold=0.5,
overlap=0.25,
nms_iou_threshold=0.5,
min_object_area=100,
max_object_area=None,
mask_threshold=0.5,
simplify_tolerance=1.0,
)
output_path = "naip_buildings.geojson"
gdf = extractor.process_raster(
raster_path,
output_path="buildings.geojson",
batch_size=4,
confidence_threshold=0.5,
overlap=0.25,
nms_iou_threshold=0.5,
min_object_area=100,
max_object_area=None,
mask_threshold=0.5,
simplify_tolerance=1.0,
)
Processing with parameters: - Confidence threshold: 0.5 - Tile overlap: 0.25 - Chip size: (512, 512) - NMS IoU threshold: 0.5 - Mask threshold: 0.5 - Min object area: 100 - Max object area: None - Simplify tolerance: 1.0 - Filter edge objects: True - Edge buffer size: 20 pixels Dataset initialized with 3 rows and 7 columns of chips Image dimensions: 2503 x 1126 pixels Chip size: 512 x 512 pixels Overlap: 25.0% (stride_x=384, stride_y=384) CRS: EPSG:26911
Processing raster with 6 batches
0%| | 0/6 [00:00<?, ?it/s]
17%|█▋ | 1/6 [00:10<00:53, 10.69s/it]
33%|███▎ | 2/6 [00:22<00:44, 11.21s/it]
50%|█████ | 3/6 [00:33<00:33, 11.28s/it]
67%|██████▋ | 4/6 [00:44<00:22, 11.31s/it]
83%|████████▎ | 5/6 [00:56<00:11, 11.25s/it]
100%|██████████| 6/6 [00:58<00:00, 8.38s/it]
100%|██████████| 6/6 [00:58<00:00, 9.82s/it]
Objects before filtering: 711 Objects after filtering: 711 Saved 711 objects to buildings.geojson
Regularize building footprints¶
In [10]:
Copied!
gdf_regularized = extractor.regularize_buildings(
gdf=gdf,
min_area=100,
angle_threshold=15,
orthogonality_threshold=0.3,
rectangularity_threshold=0.7,
)
gdf_regularized = extractor.regularize_buildings(
gdf=gdf,
min_area=100,
angle_threshold=15,
orthogonality_threshold=0.3,
rectangularity_threshold=0.7,
)
Regularizing 711 objects... - Angle threshold: 15° from 90° - Min orthogonality: 30.0% of angles - Min rectangularity: 70.0% of bounding box area
0%| | 0/711 [00:00<?, ?it/s]
20%|██ | 144/711 [00:00<00:00, 1436.20it/s]
41%|████ | 288/711 [00:00<00:00, 1438.36it/s]
62%|██████▏ | 440/711 [00:00<00:00, 1472.85it/s]
84%|████████▎ | 594/711 [00:00<00:00, 1495.53it/s]
100%|██████████| 711/711 [00:00<00:00, 1508.56it/s]
Regularization completed: - Total objects: 711 - Rectangular objects: 664 (93.4%) - Other regularized objects: 0 (0.0%) - Unmodified objects: 47 (6.6%)
Visualize building footprints¶
In [11]:
Copied!
gdf.head()
gdf.head()
Out[11]:
| geometry | confidence | class | |
|---|---|---|---|
| 991 | POLYGON ((455092.8 5277652.2, 455092.2 5277651... | 0.988162 | 1 |
| 957 | POLYGON ((455041.2 5277874.2, 455041.2 5277866... | 0.987419 | 1 |
| 435 | POLYGON ((455041.2 5277842.4, 455040.6 5277841... | 0.987318 | 1 |
| 469 | POLYGON ((455072.4 5277718.2, 455071.8 5277717... | 0.986584 | 1 |
| 436 | POLYGON ((455003.4 5277738.6, 455002.8 5277738... | 0.986499 | 1 |
In [12]:
Copied!
geoai.view_vector_interactive(
gdf, column="confidence", layer_name="Building", tiles="Satellite"
)
geoai.view_vector_interactive(
gdf, column="confidence", layer_name="Building", tiles="Satellite"
)
Out[12]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [13]:
Copied!
geoai.view_vector_interactive(
gdf, column="confidence", layer_name="Building", tiles=raster_url
)
geoai.view_vector_interactive(
gdf, column="confidence", layer_name="Building", tiles=raster_url
)
Out[13]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [14]:
Copied!
geoai.view_vector_interactive(
gdf_regularized, column="confidence", layer_name="Building", tiles=raster_url
)
geoai.view_vector_interactive(
gdf_regularized, column="confidence", layer_name="Building", tiles=raster_url
)
Out[14]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [15]:
Copied!
extractor.visualize_results(raster_path, gdf, output_path="naip_buildings.png")
extractor.visualize_results(raster_path, gdf, output_path="naip_buildings.png")
Using confidence values (range: 0.51 - 0.99)
Visualization saved to naip_buildings.png
Sample visualization saved to naip_buildings_sample.png
In [16]:
Copied!
extractor.visualize_results(
raster_path, gdf_regularized, output_path="naip_buildings_regularized.png"
)
extractor.visualize_results(
raster_path, gdf_regularized, output_path="naip_buildings_regularized.png"
)
Using confidence values (range: 0.51 - 0.99)
Visualization saved to naip_buildings_regularized.png
Sample visualization saved to naip_buildings_regularized_sample.png